﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;

namespace CalculatorLogic
{
    public class EquationParser
    {
        private readonly TokenHelper _tokenHelper = new TokenHelper();
        private readonly Queue<string> _output = new Queue<string>();
        private readonly Stack<string> _operators = new Stack<string>();        

        public string Parse(string currentExpression)
        {

            MatchCollection matches = Regex.Matches(currentExpression, @"\d\(");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, match.Value[0] + " * (");
            }
            matches = Regex.Matches(currentExpression, @"\)\d");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, ") * " + match.Value[1]);
            }

            matches = Regex.Matches(currentExpression, @"\dπ");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, match.Value[0] + " * π");
            }
            matches = Regex.Matches(currentExpression, @"π\d");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, "π * " + match.Value[0]);
            }

            matches = Regex.Matches(currentExpression, @"\de");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, match.Value[0] + " * e");
            }
            matches = Regex.Matches(currentExpression, @"e\d");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, "e * " + match.Value[1]);
            }

            matches = Regex.Matches(currentExpression, @"\d[CSLT]");
            foreach (Match match in matches)
            {
                currentExpression = currentExpression.Replace(match.Value, match.Value[0] + " * " + match.Value[1]);
            }

            currentExpression = currentExpression.Replace("π", Math.PI.ToString());
            currentExpression = currentExpression.Replace("e", Math.E.ToString());
            currentExpression = currentExpression.Replace("-(", "- (");
            currentExpression = currentExpression.Replace(")(", ") * (");         
            

            List<string> tokens = currentExpression.Split(new char[] { ' ' }).ToList();
            foreach (string token in tokens)
            {
                if (_tokenHelper.IsNumber(token))
                {
                    _output.Enqueue(token);
                }
                else if (_tokenHelper.IsFunction(token))
                {
                    _operators.Push(token);
                }
                else if (token.Equals(","))
                {
                    while (_operators.Count > 0 && _operators.Peek() != "(")
                    {
                        string topOperator = _operators.Pop();
                        _output.Enqueue(topOperator);
                    }
                }
                else if (_tokenHelper.IsOperator(token))
                {
                    while (_operators.Count > 0 && _tokenHelper.IsOperator(_operators.Peek()))
                    {
                        if ((_tokenHelper.IsLeftAssociative(token) &&
                            _operators.Count > 0 &&
                            (_tokenHelper.GetPrecedenceFor(token) <= _tokenHelper.GetPrecedenceFor(_operators.Peek()))) || (_tokenHelper.IsRightAssociative(token) &&
                            (_tokenHelper.GetPrecedenceFor(token) < _tokenHelper.GetPrecedenceFor(_operators.Peek()))))
                        {
                            string operatorToReturn = _operators.Pop();
                            _output.Enqueue(operatorToReturn);
                        }
                        else break;
                    }
                    _operators.Push(token);
                }
                if (token.Equals("("))
                {
                    _operators.Push(token);
                }
                if (token.Equals(")"))
                {
                    while (_operators.Count > 0 && _operators.Peek() != "(")
                    {
                        _output.Enqueue(_operators.Pop());
                    }
                    _operators.Pop();
                }
                if (_operators.Count > 0 && _operators.Count > 0 && _tokenHelper.IsFunction(_operators.Peek()))
                {
                    _output.Enqueue(_operators.Pop());
                }
            }
            while (_operators.Count > 0 && _tokenHelper.IsOperator(_operators.Peek()))
            {
                _output.Enqueue(_operators.Pop());
            }
            string transformedString = string.Empty;
            while (_output.Count > 0)
            {
                transformedString += _output.Dequeue() + " ";
            }
            return transformedString.TrimEnd();
        }
    }
}